# 调用内置或三方模块
import os
import cv2
import sys

# 基类
class CharFrame():

    ascii_char = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. "

    # 像素映射到字符
    def pixelToChar(self, luminance):
        return self.ascii_char[int(luminance/256*len(self.ascii_char))]

    # 将普通帧转为 ASCII 字符帧
    # limitSize 参数接受一个元组，表示图片的限宽限高。
    # fill 表示是否用空格填充图片宽度至限宽，wrap 表示是否在行末添加换行符
    def convert(self, img, limitSize=-1, fill=False, wrap=False):
        if limitSize != -1 and (img.shape[0] > limitSize[1] or img.shape[1] > limitSize[0]):
            img = cv2.resize(img, limitSize, interpolation=cv2.INTER_AREA)
        ascii_frame = ''
        blank = ''
        if fill:
            blank += ' '*(limitSize[0]-img.shape[1])
        if wrap:
            blank += '\n'
        for i in range(img.shape[0]): # shape 为元组 图片的（宽，高）
            for j in range(img.shape[1]):
                ascii_frame += self.pixelToChar(img[i,j])
            ascii_frame += blank  #问：blank相当于换行作用吗？
        return ascii_frame


# 定义I2Char继承与基类CharFrame

class I2Char(CharFrame):
    result = None
    def __init__(self, path, limitSize=-1, fill=False, wrap=False):
        self.genCharImage(path, limitSize, fill, wrap)
    #   genCharImage方法中调用基类中的convert方法实现将image对象输入，以str对象返回给函数
    def genCharImage(self, path, limitSize=-1, fill=False, wrap=False):
        # 给self.result 字符画字符串赋值
        img = cv2.imread(path,cv2.IMREAD_GRAYSCALE)
        # os.get_terminal_size()方法是获取当前终端窗口的大小
        frame = self.convert(img,os.get_terminal_size(),fill=True)
        self.result = frame

    # 定义播放方法
    def show(self, stream=2):
        if self.result is None:
            return
        if stream == 1 and os.isatty(sys.stdout.fileno()):
            self.streamOut = sys.stdout.write
            self.streamFlush = sys.stdout.flush
        elif stream == 2 and os.isatty(sys.stderr.fileno()):
            self.streamOut = sys.stderr.write
            self.streamFlush = sys.stderr.flush
        elif hasattr(stream, 'write'):
            self.streamOut = stream.write
            self.streamFlush = stream.flush
        self.streamOut(self.result)
        self.streamFlush()
        self.streamOut('\n')

# 主函数
if __name__ == '__main__':
    import argparse
    # 设置命令行参数
    parser = argparse.ArgumentParser()
    # 在命令行中输入.py文件后可加入必须参数（图片/视频路径）、可选短参数、可选长参数
    parser.add_argument('file',
                        help='Image file or charimage file')
    # .py文件执行后除了在终端展示外，将以txt文件格式保存到当前.py文件路径下
    parser.add_argument('-e', '--export', nargs='?', const='charimage.txt',
                        help='Export charimage file')
    # 获取参数
    args = parser.parse_args()
    # 实例化一个I2Char类对象
    I2Char = I2Char(args.file)
    # 调用I2Char类中的播放方法，实现在终端的显示
    I2Char.show()








